Программирование сетевых приложений

Базовые конструкции и основные элементы языка C++ и Qt

Программирование сетевых приложений

Содержание лекции

  • Переменные и типы данных
  • Преобразование и приведение типов
  • Динамическая инициализация
  • Область действия и время жизни переменных
  • Циклы и логические конструкции
  • Массивы и строки
  • Особенности Qt-типов
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Переменные и типы данных в C++

// Целочисленные типы
int counter = 42;           // 32-битное целое
long long bigNumber = 1234567890LL;  // 64-битное целое
unsigned int positive = 100;         // Беззнаковое целое

// Типы с плавающей точкой
float pi = 3.14f;           // 32-битное число
double precise = 3.14159265359;     // 64-битное число

// Символьные типы
char symbol = 'A';          // Один символ
wchar_t wideChar = L'Б';    // Широкий символ
char16_t utf16 = u'ю';      // UTF-16 символ
char32_t utf32 = U'😀';     // UTF-32 символ

// Логический тип
bool isConnected = true;    // true или false
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Квалификаторы типов

// Квалификатор const - неизменяемость
const int MAX_CONNECTIONS = 100;
const double PI = 3.14159;

// Квалификатор constexpr - константа времени компиляции
constexpr int BUFFER_SIZE = 1024;
constexpr double EULER_NUMBER = 2.71828;

// Квалификатор volatile - запрет оптимизации
volatile bool dataReady = false;  // Может измениться вне программы

// Квалификатор mutable - возможность изменения в const-методах
class NetworkBuffer {
private:
    mutable int accessCount = 0;
    
public:
    void process() const {
        accessCount++;  // Допустимо благодаря mutable
    }
};
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Пользовательские типы данных

// Перечисления (enum) — имена попадают в общую область видимости
enum ConnectionState {
    DISCONNECTED,
    CONNECTING,
    CONNECTED,
    ERROR_STATE
};

// Перечисления с областью видимости (enum class) — рекомендуется
enum class ProtocolType {
    TCP,
    UDP,
    HTTP,
    WebSocket
};

// Структуры (struct)
struct NetworkPacket {
    int packetId;
    std::string data;
    time_t timestamp;
};

// Объединения (union) — в современном C++ лучше использовать std::variant
union DataValue {
    int integer;
    float floating;
    char string[8];
};
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Преобразование типов в C++

Неявное преобразование (автоматическое)

int x = 10;
double y = x;           // Неявное преобразование int -> double
char c = 'A';
int code = c;           // Неявное преобразование char -> int

// Потеря точности
double precise = 3.14159;
int truncated = precise;  // 3 (дробная часть отбрасывается)
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Явное преобразование (приведение типов)

// Старый стиль C — избегать!
int oldStyle = (int)3.14;

// Новый стиль C++ — предпочитать
double value = 3.14;
int cast1 = static_cast<int>(value);        // Безопасное приведение
int* ptr = nullptr;
void* voidPtr = reinterpret_cast<void*>(ptr);  // Приведение указателей

// Приведение const
const int constValue = 42;
int* nonConst = const_cast<int*>(&constValue);  // Удаление const

// Приведение с проверкой (для полиморфных типов)
class Base { virtual void foo() {} };
class Derived : public Base { void bar() {} };

Base* base = new Derived();
Derived* derived = dynamic_cast<Derived*>(base);  // Проверка времени выполнения
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Расширение типов (Type Promotion)

// Автоматическое расширение в выражениях
short s1 = 10, s2 = 20;
int result = s1 + s2;    // short расширяется до int

// Правила расширения
char c = 'A';
int i = 50;
float f = 1.5f;

auto sum = c + i + f;    // char -> int -> float

// Расширение в функциях
void processValue(int value) { /* ... */ }

short shortValue = 100;
processValue(shortValue);  // Автоматическое расширение short -> int
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Динамическая инициализация

Инициализация переменных

// Прямая инициализация
int port(8080);
std::string server("localhost");

// Список инициализации (C++11) — рекомендуется
int bufferSize{4096};
double timeout{30.5};

// Автоматический вывод типа (C++11)
auto portNumber = 8080;        // int
auto serverName = "localhost"; // const char*
auto piValue = 3.14159;        // double

// Инициализация nullptr (C++11)
int* pointer = nullptr;        // Современный способ обозначения нулевого указателя
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Инициализация в Qt

#include <QString>
#include <QVector>
#include <QMap>

// Инициализация QString
QString message = "Hello, Qt!";
QString emptyString;  // Пустая строка

// Инициализация контейнеров Qt
QVector<int> numbers = {1, 2, 3, 4, 5};  // Список инициализации
QMap<QString, int> settings = {
    {"timeout", 30},
    {"retries", 3},
    {"port", 8080}
};

// Инициализация сетевых классов Qt
#include <QHostAddress>
QHostAddress localHost("127.0.0.1");
QHostAddress anyAddress = QHostAddress::Any;
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Область действия переменных (Scope)

Глобальная область видимости

// Глобальные переменные — минимизировать использование!
int globalConnectionCount = 0;
const int MAX_BUFFER_SIZE = 4096;

// Пространство имен — предпочтительный способ организации
namespace NetworkConfig {
    const std::string DEFAULT_HOST = "localhost";
    const int DEFAULT_PORT = 8080;
}

void function() {
    std::cout << NetworkConfig::DEFAULT_HOST << std::endl;
}
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Локальная область видимости

void processData() {
    int localCounter = 0;  // Локальная переменная
    
    if (true) {
        int blockScoped = 42;  // Область видимости - блок if
        localCounter = blockScoped;
    }
    // blockScoped недоступен здесь
    
    for (int i = 0; i < 10; i++) {
        // i доступен только внутри цикла
        localCounter += i;
    }
    // i недоступен здесь
}
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Время жизни переменных (Lifetime)

Автоматическое время жизни

void function() {
    int autoVariable = 10;  // Создается при входе в блок
    // ... использование переменной
}  // Уничтожается при выходе из блока — вызывается деструктор
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Статическое время жизни

void counterFunction() {
    static int callCount = 0;  // Инициализируется один раз
    callCount++;
    std::cout << "Function called " << callCount << " times" << std::endl;
}

class NetworkServer {
private:
    static int instanceCount;  // Статический член класса
    // ...
};

// Определение вне класса
int NetworkServer::instanceCount = 0;
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Динамическое время жизни

// Ручное управление — избегать в современном C++!
int* dynamicArray = new int[100];
for (int i = 0; i < 100; i++) {
    dynamicArray[i] = i * i;
}
delete[] dynamicArray;  // Забыли — утечка памяти

// Современный подход: умные указатели (C++11)
#include <memory>
auto smartArray = std::make_unique<int[]>(100);  // Авто-освобождение
smartArray[0] = 8080;

// Для совместного владения
auto sharedData = std::make_shared<NetworkPacket>();
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Условные конструкции

Оператор if-else

int checkConnectionStatus(int port) {
    if (port < 0 || port > 65535) {
        return -1;  // Неверный порт
    } else if (port < 1024) {
        return 0;   // Системный порт (requires root/Admin)
    } else {
        return 1;   // Пользовательский порт
    }
}

// Тернарный оператор
std::string getStatus(bool isConnected) {
    return isConnected ? "Connected" : "Disconnected";
}
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Оператор switch

std::string getProtocolName(int protocol) {
    switch (protocol) {
        case 6:
            return "TCP";
        case 17:
            return "UDP";
        case 80:
            return "HTTP";
        case 443:
            return "HTTPS";
        default:
            return "Unknown";
    }
}

// Switch с несколькими case
std::string getServiceType(int port) {
    switch (port) {
        case 21: case 22: case 23:
            return "Remote Access";
        case 25: case 587:
            return "Email";
        case 80: case 443: case 8080:
            return "Web Service";
        default:
            return "Other";
    }
}
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Циклы в C++

Цикл for

// Классический for
for (int i = 0; i < 10; i++) {
    std::cout << "Iteration: " << i << std::endl;
}

// For с несколькими переменными
for (int i = 0, j = 10; i < j; i++, j--) {
    std::cout << i << " " << j << std::endl;
}

// Бесконечный цикл
for (;;) {
    if (condition) break;
    // ...
}

// Диапазонный for (C++11) — предпочтительный способ
std::vector<int> ports = {80, 443, 8080, 3000};
for (int port : ports) {
    std::cout << "Port: " << port << std::endl;
}
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Цикл while

// Предусловный цикл — тело может не выполниться ни разу
int attempts = 0;
while (attempts < 3 && !isConnected) {
    connectToServer();
    attempts++;
}

// Паттерн retry с экспоненциальной задержкой
int retries = 0;
while (retries < MAX_RETRIES) {
    if (tryConnect()) break;
    std::this_thread::sleep_for(std::chrono::milliseconds(100 * (1 << retries)));
    retries++;
}
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Цикл do-while

// Постусловный цикл — тело выполняется хотя бы один раз
char choice;
do {
    std::cout << "Continue? (y/n): ";
    std::cin >> choice;
} while (choice == 'y' || choice == 'Y');

// Меню с гарантированным первым выполнением
int option;
do {
    showMenu();
    std::cin >> option;
    processMenuOption(option);
} while (option != 0);
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Управление циклами

// Оператор break - выход из цикла
for (int port = 1; port <= 65535; port++) {
    if (isPortOpen(port)) {
        std::cout << "Found open port: " << port << std::endl;
        break;  // Выход при первом найденном открытом порте
    }
}

// Оператор continue - переход к следующей итерации
std::vector<int> ports = {21, 22, 80, 443, 8080, 3306};
for (int port : ports) {
    if (isPortReserved(port)) {
        continue;  // Пропустить зарезервированные порты
    }
    scanPort(port);
}

// Выход из вложенных циклов через флаг (C++ не поддерживает break label)
bool found = false;
for (int i = 0; i < 10 && !found; i++) {
    for (int j = 0; j < 10; j++) {
        if (i * j > 50) {
            found = true;  // Флаг для выхода из внешнего цикла
            break;         // Выход из внутреннего цикла
        }
    }
}
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Массивы в C++

Статические массивы

// Одномерные массивы
int ports[5] = {80, 443, 8080, 3000, 9000};
char message[] = "Hello, Network!";  // Автоматический размер = 16 (с \0)

// Двумерные массивы
int matrix[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// Массивы без инициализации
int buffer[1024];  // Содержит мусор!
int zeros[256] = {0};  // Все элементы = 0

// Предпочтительный вариант (C++11)
#include <array>
std::array<int, 5> safePorts = {80, 443, 8080, 3000, 9000};
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Работа с массивами

// Доступ к элементам
int firstPort = ports[0];      // 80 — без проверки границ
int lastPort = ports[4];       // 9000

// Безопасный доступ через std::array
int safe = safePorts.at(0);    // Бросает std::out_of_range

// Изменение элементов
ports[2] = 8888;  // Заменить 8080 на 8888

// Перебор массива
for (int i = 0; i < 5; i++) {
    std::cout << "Port " << i << ": " << ports[i] << std::endl;
}

// Ошибка: выход за границы — НЕПРЕДСКАЗУЕМОЕ ПОВЕДЕНИЕ!
// int invalid = ports[10];  // UB: может упасть, а может и нет
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Динамические массивы

// Raw new[] — избегать в современном коде
int* dynamicPorts = new int[10];
for (int i = 0; i < 10; i++) {
    dynamicPorts[i] = 1000 + i * 100;
}
std::cout << "Port 5: " << dynamicPorts[5] << std::endl;  // 1500
delete[] dynamicPorts;  // Забыли delete[] — утечка памяти!

// Современный подход: std::vector — предпочтительный выбор
#include <vector>
std::vector<int> ports = {80, 443, 8080};
ports.push_back(3000);   // Автоматическое управление памятью
ports.resize(100);       // Изменение размера
// Освобождение — автоматически при выходе из области видимости
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Строки в C++

C-style строки

// Создание C-строк — избегать в новом коде!
char cString1[] = "Network";
char cString2[20] = "Programming";
const char* cString3 = "C++";

// Работа с C-строками
#include <cstring>
char buffer[50];
strcpy(buffer, "Hello ");          // Нет проверки переполнения!
strcat(buffer, "World");           // Нет проверки переполнения!
int length = strlen(buffer);

// Безопасные альтернативы
strncpy(buffer, "Hello", sizeof(buffer) - 1);
strncat(buffer, " World", sizeof(buffer) - strlen(buffer) - 1);
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

C++ строки (std::string)

#include <string>

// Создание строк
std::string str1 = "Network";
std::string str2("Programming");
std::string str3 = str1 + " " + str2;  // "Network Programming"

// Методы строк
int len = str1.length();          // Длина
char first = str1[0];            // Первый символ
std::string sub = str1.substr(0, 4);  // "Netw"

// Поиск и замена
size_t pos = str3.find("Prog");
if (pos != std::string::npos) {
    str3.replace(pos, 4, "Development");
}

// Преобразование чисел
int port = 8080;
std::string portStr = std::to_string(port);
int portNum = std::stoi(portStr);
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

QString в Qt

#include <QString>
#include <QDebug>

// Создание QString
QString qtString1 = "Qt Network";
QString qtString2 = QString("Programming");
QString qtString3 = qtString1 + " " + qtString2;

// Преобразования
std::string stdStr = qtString3.toStdString();
const char* cStr = qtString3.toLocal8Bit().constData();

// Форматирование (аналог sprintf)
QString formatted = QString("Server %1:%2 is %3")
                   .arg("localhost")
                   .arg(8080)
                   .arg("running");

// Работа с Unicode
QString unicode = QString::fromUtf8("Привет, мир!");
QString fromStd = QString::fromStdString("C++ string");

// Полезные методы
bool startsWith = qtString1.startsWith("Qt");
bool endsWith = qtString1.endsWith("Network");
QString upper = qtString1.toUpper();
QString lower = qtString1.toLower();
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Контейнеры Qt для массивов

#include <QVector>
#include <QList>
#include <QMap>
#include <QHash>

// QVector - динамический массив (в Qt 6 QList = QVector)
QVector<int> ports;
ports.append(80);
ports.append(443);
ports << 8080 << 3000;  // Оператор <<

int first = ports.first();    // 80
int last = ports.last();      // 3000

// QList - список (оптимизирован для Qt)
QList<QString> protocols;
protocols << "TCP" << "UDP" << "HTTP";

// QMap - ассоциативный массив (отсортированный)
QMap<QString, int> portMap;
portMap["HTTP"] = 80;
portMap["HTTPS"] = 443;

// QHash - хеш-таблица (быстрее, но не отсортирована)
QHash<QString, int> fastPortMap;
fastPortMap["FTP"] = 21;
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Современные особенности C++11 и выше

// Автоматический вывод типа
auto port = 8080;                    // int
auto server = "localhost";           // const char*
auto config = NetworkConfig("srv", 80);  // NetworkConfig

// Универсальная инициализация
int ports[] = {80, 443, 8080};
std::vector<int> portsVec{80, 443, 8080};
std::map<std::string, int> settings{
    {"timeout", 30},
    {"retries", 3}
};

// nullptr вместо NULL
int* pointer = nullptr;  // Безопасный нулевой указатель

// Range-based for с const auto&
std::vector<std::string> protocols = {"TCP", "UDP", "HTTP"};
for (const auto& proto : protocols) {
    std::cout << proto << std::endl;
}
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Заключение

Основные концепции:

  • Переменные и типы — фундамент любой программы
  • Преобразование типов — важно для предотвращения ошибок
  • Область видимости и время жизни — критичны для управления ресурсами
  • Циклы и условия — управление потоком выполнения
  • Массивы и строки — основы работы с данными
  • Qt-типы — расширение возможностей стандартных типов
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Рекомендации:

  • Используйте современные конструкции C++11+ (auto, nullptr, range-for)
  • Предпочитайте std::string и QString C-строкам
  • Используйте std::vector / std::array вместо C-массивов
  • Управляйте памятью через умные указатели (RAII)
  • Следите за областью видимости — объявляйте переменные минимально
  • В Qt используйте QString для Unicode и Qt-контейнеры для совместимости
Базовые конструкции и основные элементы языка
Программирование сетевых приложений

Вопросы для самопроверки

  1. Чем отличаются const и constexpr?
  2. Какие существуют способы приведения типов в C++?
  3. В чём различие между std::string и QString?
  4. Как управлять временем жизни динамически выделенных объектов?
  5. Когда использовать QVector, а когда QList?
  6. Что такое области видимости и как они влияют на доступ к переменным?
  7. Какие преимущества даёт использование диапазонных циклов?
  8. Почему в C++ нет labeled break и как выйти из вложенных циклов?
Базовые конструкции и основные элементы языка

Лекция посвящена фундаментальным конструкциям C++ и базовым типам Qt. Цель — систематизировать знания о типах данных, управлении памятью и потоке выполнения, которые потребуются для сетевого программирования. Акцент на современных конструкциях C++11 и выше.

Порядок тем: от простых типов к управлению памятью, затем управление потоком, структуры данных и в конце — Qt-расширения. На лекцию рассчитывайте ~90 минут.

Размеры типов зависят от платформы: int обычно 4 байта, но стандарт гарантирует лишь int >= 2 байта. Для сетевого кода используйте типы с фиксированным размером: int32_t, uint16_t из <cstdint>. float — 4 байта, double — 8 байт. В сетевых приложениях double предпочтительнее для точных вычислений. bool занимает 1 байт.

const: значение нельзя изменить после инициализации. constexpr: вычисляется на этапе компиляции — быстрее, но ограничено константными выражениями. Встраивайте constexpr-функции для вычисления размеров буферов и таймаутов. volatile: компилятор НЕ кэширует значение в регистре — важно для сигналов от оборудования и multi-threaded флагов. mutable: «легальный обход» const — используется для кэширования, логирования, подсчёта обращений.

Ключевое отличие enum от enum class: обычный enum «загрязняет» пространство имён — DISCONNECTED виден везде. enum class требует указания ProtocolType::TCP, что предотвращает конфликты. Рекомендуйте студентам всегда использовать enum class. union — экономит память, но небезопасен. В C++17 появился std::variant<int, float, std::string> — типобезопасная замена.

Неявное расширение (int -> double) безопасно. Сужение (double -> int) происходит молча и теряет данные — частый источник багов. Компилятор может выдать warning; включите -Wconversion.

static_cast — наиболее частый, проверяется компилятором. reinterpret_cast — побитовое переосмысление, опасно, используйте только для низкоуровневой работы с буферами (сетевые пакеты). dynamic_cast — работает только с полиморфными типами (есть virtual), возвращает nullptr если приведение неверно. Требует RTTI. const_cast — снятие/добавление const; изменение изначально const объекта — UB (undefined behavior).

Правило integer promotion: все типы меньше int (char, short, bool) расширяются до int перед арифметическими операциями. Иерархия: int -> unsigned int -> long -> unsigned long -> long long -> float -> double -> long double. В сетевых протоколах важно учитывать расширение при побитовых операциях: uint8_t flag = 0x80; auto x = ~flag; // x — int, не uint8_t!

Фигурные скобки {} — «uniform initialization» — предотвращает сужающее преобразование: int x{3.14}; — ошибка компиляции! Рекомендуйте {} как стиль по умолчанию. auto повышает читаемость, но помните: auto x = "hello" — это const char*, не std::string. Используйте auto с явным типом инициализатора. nullptr заменяет NULL и 0 — типобезопасно, неявно не преобразуется в integer.

Qt-типы имеют неявное совместное использование данных (copy-on-write), поэтому копирование QString/QVector дешёвое. QHostAddress — основной класс для работы с IP-адресами в Qt Network. QHostAddress::Any — слушает на всех интерфейсах (0.0.0.0).

Глобальные переменные — зло: затрудняют отладку, не потокобезопасны, нарушают инкапсуляцию. Избегайте их, кроме констант. Пространства имён — лучший способ группировки. Можно вкладывать: namespace Net { namespace Tcp { ... } }. В Qt используется D-указатель (Pimpl-идиома) для сокрытия данных.

Правило: объявляйте переменные как можно ближе к месту использования. C++17 добавил if с инициализатором: if (auto it = map.find(key); it != map.end()) { ... } Полезно для ограничения области видимости.

Автоматические переменные живут на стеке — быстро, безопасно. Деструктор вызывается автоматически при выходе из области видимости. Это основа идиомы RAII — Resource Acquisition Is Initialization. Все ресурсы (файлы, сокеты, блокировки) оборачивайте в классы с деструкторами.

static-переменная в функции: живёт всё время работы программы, но видна только внутри функции. Потокобезопасная инициализация в C++11 (magic statics). static-член класса: один экземпляр на все объекты. Полезен для подсчёта подключений, пула ресурсов. Внимание: порядок уничтожения static-объектов в разных единицах трансляции не определён — возможно static destruction order fiasco.

new/delete — главная источник утечек памяти и ошибок. Правило: НИКОГДА не используйте raw new/delete в прикладном коде. unique_ptr — единоличное владение, нулевой overhead. shared_ptr — разделяемое владение, есть overhead (control block). make_unique/make_shared — безопаснее (exception safety). В Qt есть альтернатива: QScopedPointer, QSharedPointer.

if с инициализатором (C++17): if (auto socket = connect(); socket != nullptr) { ... } Полезно для ограничения области видимости переменной условия. Тернарный оператор — выражение, возвращает значение. Не вкладывайте тернарные операторы друг в друга — нечитаемо.

switch работает только с целыми типами и enum. Забытый break — классическая ошибка (fall-through). C++17: [[fallthrough]] атрибут для явного указания намеренного проваливания. Компиляторы с -Wimplicit-fallthrough предупреждают. Для строк и сложных типов используйте if-else или std::map. C++23 добавит std::expected и pattern matching через inspect.

Классический for — когда нужен индекс или сложная логика. Range-based for — чище и безопаснее, невозможно выйти за границы. Внимание: for (auto x : container) копирует элементы! Используйте const auto& для тяжёлых объектов. Бесконечный for(;;) — идиоматичнее чем while(true).

Классический паттерн для повторных попыток подключения. В сетевых приложениях обязательно ограничивайте число попыток и добавляйте задержку (exponential backoff), чтобы не перегрузить сервер.

do-while гарантирует хотя бы одно выполнение тела. Часто используется для: меню, валидация ввода, первичная попытка подключения. Иногда вместо do-while лучше использовать while(true) + break — условие выхода становится более читаемым.

break — выход из ближайшего цикла или switch. continue — переход к следующей итерации. ВНИМАНИЕ: в C++ НЕТ labeled break (как в Java). Для выхода из вложенных циклов используйте: флаг, goto (крайне не рекомендуется), или вынесите внутренний цикл в отдельную функцию с return.

Статические массивы: размер известен на этапе компиляции. Локальные массивы без инициализации содержат мусор — частый баг. std::array — обёртка над C-массивом: знает свой размер, поддерживает range-based for, at() с проверкой границ, нулевой overhead. В сетевом коде: буферы фиксированного размера для приёма пакетов.

operator[] — без проверки, O(1), но при выходе за границы — UB. at() — с проверкой, бросает исключение. В production лучше at() или статический анализ. UB — худший тип ошибки: программа «работает» пока не сломается в неожиданный момент. Используйте AddressSanitizer для отладки: -fsanitize=address -fsanitize=undefined.

new[]/delete[] — забытый delete[] = утечка памяти. Исключение между new и delete = утечка. Никогда не используйте в современном C++. std::vector — стандартный динамический массив. Управляет памятью сам, поддерживает random access, итераторы, range-based for. reserve() — если знаете размер заранее, избегаете реаллокаций. В сетевом коде: vector<uint8_t> для буферов приёма/передачи.

C-строки — массивы char, завершающиеся нулевым символом '\0'. strcpy/strcat — НЕ проверяют размер буфера → buffer overflow, частая уязвимость в безопасности. Используйте strncpy/strncat или, лучше, вообще std::string. В сетевых протоколах C-строки встречаются в API операционной системы (POSIX sockets). Конвертируйте в std::string как можно раньше.

std::string — основной строковый тип C++. Управляет памятью автоматически, поддерживает конкатенацию через +. Small String Optimization (SSO): короткие строки (~15 символов) хранятся внутри объекта, без heap-аллокации. find() возвращает std::string::npos если не найдено. stoi/stol/stof/stod — преобразование строки в число. Бросают исключения при ошибке. В Qt: QString::toInt() возвращает bool через параметр.

QString — Unicode (UTF-16) строка, основа Qt. Аргументы через .arg() безопаснее sprintf — нет проблем с типами. toStdString() — конвертация в std::string (UTF-8 в Qt 6). toLocal8Bit() — в локальной кодировке, может быть некорректно. Всегда используйте QString::fromUtf8() для явного указания кодировки. QDebug: qDebug() << qtString1; — удобный вывод для отладки.

Qt 6: QList и QVector объединены — QList теперь реализован как QVector. QMap — красно-чёрное дерево, O(log n) поиск, отсортированные ключи. QHash — хеш-таблица, O(1) амортизированный поиск. Выбор: если нужен порядок ключей — QMap, иначе QHash (быстрее). Java-style итераторы (QListIterator) устарели — используйте range-based for или STL-итераторы.

auto — вывод типа компилятором. Улучшает читаемость при сложных типых: auto it = map.find(key) вместо map<string,int>::iterator. const auto& — ссылка, избегает копирования. Ключевое слово! nullptr — типобезопасная замена NULL (который был int 0). Современный C++ (14/17/20): if constexpr, structured bindings, concepts, ranges — если интересно, изучите дополнительно.

Резюме: лекция покрыла фундамент C++ и Qt, необходимый для сетевого программирования. Главное — использовать современные конструкции и избегать опасных паттернов (raw pointers, C-строки, глобальные переменные).

Для следующей лекции: будем изучать структуры классов, наследование и полиморфизм — ключевые механизмы ООП в контексте сетевых приложений.

Вопросы для проверки усвоения материала. Особое внимание — вопросам 4 (RAII/умные указатели) и 8 (нет labeled break — важно!). Ответы: 1) const — неизменяемость, constexpr — вычисление при компиляции; 4) unique_ptr/shared_ptr, RAII; 5) в Qt6 — одинаковы; 8) флаг, goto, вынесение в функцию с return.